package com.lagou.boot;

import com.lagou.client.RPCConsumer;
import com.lagou.service.IUserService;
import org.I0Itec.zkclient.ZkClient;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ConsumerBoot {

    public static final String namespace = "/rpc";

    private static ZkClient client;

    public static final String zkAddress = "39.108.102.154:2181";

    public static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {

        // 1.初始化zkClient
        client = new ZkClient(zkAddress);

        // 2.创建线程池用于定时上报服务的最后一次响应时间
        uoloadResponseTime();


        //3.创建代理对象
        IUserService service = (IUserService) RPCConsumer.createProxy(IUserService.class);

        //4.循环给服务器写数据
        while (true){
            String result = service.sayHello("are you ok !!");
            System.out.println(result);
            Thread.sleep(500);
        }

    }

    private static void uoloadResponseTime() {
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            List<String> serverNodes = client.getChildren(namespace);
            for (String path : serverNodes) {
                try{
                    //获取最后一次请求的系统时间
                    Long time = RPCConsumer.serverToLastTime.get(path);
                    //判断最后一次的请求时间是否超过5s
                    if(time != null && System.currentTimeMillis() - time < 5000L){
                        //没超过：直接上报，更新zk服务中对应的节点值
                        client.writeData(getFullPath(path), RPCConsumer.serverToResponseTime.get(path));
                    }else{
                        //超过：更新zk服务中对应的节点值为0
                        client.writeData(getFullPath(path), 0L);
                    }
                }catch (Exception e){
                    System.out.println("上报异常：" + e.getMessage());
                }
            }
        }, 5, 5, TimeUnit.SECONDS);
    }

    /**
     * 获取完整的path
     * @return
     */
    private static String getFullPath(String path){
        return namespace + "/" + path;
    }

    /**
     * 根据负载均衡算法得出要调用的服务器地址
     */
    public static String getServerAddress() {
        List<String> paths = new ArrayList<>();
        //time用于存储最短的响应时间
        Long time = 5000L;
        List<String> serverNodes = client.getChildren(namespace);
        for (String path : serverNodes) {
            //获取zk上存储的服务器响应时间
            Long value = client.readData(getFullPath(path));
            if(time == value){
                //服务器响应时间=最短响应时间，添加服务地址到集合中
                paths.add(path);
            } else if (time > value) {
                //服务器响应时间<最短响应时间，清空集合后添加服务地址到集合中并修改最短响应时间
                paths.clear();
                paths.add(path);
                time = value;
            }
        }
        //随机返回集合中的一个服务器地址
        return paths.get(random.nextInt(paths.size()));
    }
}
